home *** CD-ROM | disk | FTP | other *** search
/ Ultra Pack / UltraComputing Partner Applications.iso / SunLabs / tclTK / src / tk4.0 / tkImgBmap.c < prev    next >
C/C++ Source or Header  |  1995-06-28  |  30KB  |  1,002 lines

  1. /* 
  2.  * tkImgBmap.c --
  3.  *
  4.  *    This procedure implements images of type "bitmap" for Tk.
  5.  *
  6.  * Copyright (c) 1994 The Regents of the University of California.
  7.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  */
  12.  
  13. static char sccsid[] = "@(#) tkImgBmap.c 1.18 95/06/28 13:09:18";
  14.  
  15. #include "tkInt.h"
  16. #include "tkPort.h"
  17.  
  18. /*
  19.  * The following data structure represents the master for a bitmap
  20.  * image:
  21.  */
  22.  
  23. typedef struct BitmapMaster {
  24.     Tk_ImageMaster tkMaster;    /* Tk's token for image master.  NULL means
  25.                  * the image is being deleted. */
  26.     Tcl_Interp *interp;        /* Interpreter for application that is
  27.                  * using image. */
  28.     Tcl_Command imageCmd;    /* Token for image command (used to delete
  29.                  * it when the image goes away).  NULL means
  30.                  * the image command has already been
  31.                  * deleted. */
  32.     int width, height;        /* Dimensions of image. */
  33.     char *data;            /* Data comprising bitmap (suitable for
  34.                  * input to XCreateBitmapFromData).   May
  35.                  * be NULL if no data.  Malloc'ed. */
  36.     char *maskData;        /* Data for bitmap's mask (suitable for
  37.                  * input to XCreateBitmapFromData).
  38.                  * Malloc'ed. */
  39.     Tk_Uid fgUid;        /* Value of -foreground option (malloc'ed). */
  40.     Tk_Uid bgUid;        /* Value of -background option (malloc'ed). */
  41.     char *fileString;        /* Value of -file option (malloc'ed). */
  42.     char *dataString;        /* Value of -data option (malloc'ed). */
  43.     char *maskFileString;    /* Value of -maskfile option (malloc'ed). */
  44.     char *maskDataString;    /* Value of -maskdata option (malloc'ed). */
  45.     struct BitmapInstance *instancePtr;
  46.                 /* First in list of all instances associated
  47.                  * with this master. */
  48. } BitmapMaster;
  49.  
  50. /*
  51.  * The following data structure represents all of the instances of an
  52.  * image that lie within a particular window:
  53.  */
  54.  
  55. typedef struct BitmapInstance {
  56.     int refCount;        /* Number of instances that share this
  57.                  * data structure. */
  58.     BitmapMaster *masterPtr;    /* Pointer to master for image. */
  59.     Tk_Window tkwin;        /* Window in which the instances will be
  60.                  * displayed. */
  61.     XColor *fg;            /* Foreground color for displaying image. */
  62.     XColor *bg;            /* Background color for displaying image. */
  63.     Pixmap bitmap;        /* The bitmap to display. */
  64.     Pixmap mask;        /* Mask: only display bitmap pixels where
  65.                  * there are 1's here. */
  66.     GC gc;            /* Graphics context for displaying bitmap.
  67.                  * None means there was an error while
  68.                  * setting up the instance, so it cannot
  69.                  * be displayed. */
  70.     struct BitmapInstance *nextPtr;
  71.                 /* Next in list of all instance structures
  72.                  * associated with masterPtr (NULL means
  73.                  * end of list). */
  74. } BitmapInstance;
  75.  
  76. /*
  77.  * The type record for bitmap images:
  78.  */
  79.  
  80. static int        ImgBmapCreate _ANSI_ARGS_((Tcl_Interp *interp,
  81.                 char *name, int argc, char **argv,
  82.                 Tk_ImageType *typePtr, Tk_ImageMaster master,
  83.                 ClientData *clientDataPtr));
  84. static ClientData    ImgBmapGet _ANSI_ARGS_((Tk_Window tkwin,
  85.                 ClientData clientData));
  86. static void        ImgBmapDisplay _ANSI_ARGS_((ClientData clientData,
  87.                 Display *display, Drawable drawable, 
  88.                 int imageX, int imageY, int width, int height,
  89.                 int drawableX, int drawableY));
  90. static void        ImgBmapFree _ANSI_ARGS_((ClientData clientData,
  91.                 Display *display));
  92. static void        ImgBmapDelete _ANSI_ARGS_((ClientData clientData));
  93.  
  94. Tk_ImageType tkBitmapImageType = {
  95.     "bitmap",            /* name */
  96.     ImgBmapCreate,        /* createProc */
  97.     ImgBmapGet,            /* getProc */
  98.     ImgBmapDisplay,        /* displayProc */
  99.     ImgBmapFree,        /* freeProc */
  100.     ImgBmapDelete,        /* deleteProc */
  101.     (Tk_ImageType *) NULL    /* nextPtr */
  102. };
  103.  
  104. /*
  105.  * Information used for parsing configuration specs:
  106.  */
  107.  
  108. static Tk_ConfigSpec configSpecs[] = {
  109.     {TK_CONFIG_UID, "-background", (char *) NULL, (char *) NULL,
  110.     "", Tk_Offset(BitmapMaster, bgUid), 0},
  111.     {TK_CONFIG_STRING, "-data", (char *) NULL, (char *) NULL,
  112.     (char *) NULL, Tk_Offset(BitmapMaster, dataString), TK_CONFIG_NULL_OK},
  113.     {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL,
  114.     (char *) NULL, Tk_Offset(BitmapMaster, fileString), TK_CONFIG_NULL_OK},
  115.     {TK_CONFIG_UID, "-foreground", (char *) NULL, (char *) NULL,
  116.     "#000000", Tk_Offset(BitmapMaster, fgUid), 0},
  117.     {TK_CONFIG_STRING, "-maskdata", (char *) NULL, (char *) NULL,
  118.     (char *) NULL, Tk_Offset(BitmapMaster, maskDataString),
  119.     TK_CONFIG_NULL_OK},
  120.     {TK_CONFIG_STRING, "-maskfile", (char *) NULL, (char *) NULL,
  121.     (char *) NULL, Tk_Offset(BitmapMaster, maskFileString),
  122.     TK_CONFIG_NULL_OK},
  123.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  124.     (char *) NULL, 0, 0}
  125. };
  126.  
  127. /*
  128.  * The following data structure is used to describe the state of
  129.  * parsing a bitmap file or string.  It is used for communication
  130.  * between GetBitmapData and NextBitmapWord.
  131.  */
  132.  
  133. #define MAX_WORD_LENGTH 100
  134. typedef struct ParseInfo {
  135.     char *string;        /* Next character of string data for bitmap,
  136.                  * or NULL if bitmap is being read from
  137.                  * file. */
  138.     FILE *f;            /* File containing bitmap data, or NULL
  139.                  * if no file. */
  140.     char word[MAX_WORD_LENGTH+1];
  141.                 /* Current word of bitmap data, NULL
  142.                  * terminated. */
  143.     int wordLength;        /* Number of non-NULL bytes in word. */
  144. } ParseInfo;
  145.  
  146. /*
  147.  * Prototypes for procedures used only locally in this file:
  148.  */
  149.  
  150. static char *        GetBitmapData _ANSI_ARGS_((Tcl_Interp *interp,
  151.                 char *string, char *fileName,
  152.                 int *widthPtr, int *heightPtr));
  153. static int        ImgBmapCmd _ANSI_ARGS_((ClientData clientData,
  154.                 Tcl_Interp *interp, int argc, char **argv));
  155. static void        ImgBmapCmdDeletedProc _ANSI_ARGS_((
  156.                 ClientData clientData));
  157. static void        ImgBmapConfigureInstance _ANSI_ARGS_((
  158.                 BitmapInstance *instancePtr));
  159. static int        ImgBmapConfigureMaster _ANSI_ARGS_((
  160.                 BitmapMaster *masterPtr, int argc, char **argv,
  161.                 int flags));
  162. static int        NextBitmapWord _ANSI_ARGS_((ParseInfo *parseInfoPtr));
  163.  
  164. /*
  165.  *----------------------------------------------------------------------
  166.  *
  167.  * ImgBmapCreate --
  168.  *
  169.  *    This procedure is called by the Tk image code to create "test"
  170.  *    images.
  171.  *
  172.  * Results:
  173.  *    A standard Tcl result.
  174.  *
  175.  * Side effects:
  176.  *    The data structure for a new image is allocated.
  177.  *
  178.  *----------------------------------------------------------------------
  179.  */
  180.  
  181.     /* ARGSUSED */
  182. static int
  183. ImgBmapCreate(interp, name, argc, argv, typePtr, master, clientDataPtr)
  184.     Tcl_Interp *interp;        /* Interpreter for application containing
  185.                  * image. */
  186.     char *name;            /* Name to use for image. */
  187.     int argc;            /* Number of arguments. */
  188.     char **argv;        /* Argument strings for options (doesn't
  189.                  * include image name or type). */
  190.     Tk_ImageType *typePtr;    /* Pointer to our type record (not used). */
  191.     Tk_ImageMaster master;    /* Token for image, to be used by us in
  192.                  * later callbacks. */
  193.     ClientData *clientDataPtr;    /* Store manager's token for image here;
  194.                  * it will be returned in later callbacks. */
  195. {
  196.     BitmapMaster *masterPtr;
  197.  
  198.     masterPtr = (BitmapMaster *) ckalloc(sizeof(BitmapMaster));
  199.     masterPtr->tkMaster = master;
  200.     masterPtr->interp = interp;
  201.     masterPtr->imageCmd = Tcl_CreateCommand(interp, name, ImgBmapCmd,
  202.         (ClientData) masterPtr, ImgBmapCmdDeletedProc);
  203.     masterPtr->width = masterPtr->height = 0;
  204.     masterPtr->data = NULL;
  205.     masterPtr->maskData = NULL;
  206.     masterPtr->fgUid = NULL;
  207.     masterPtr->bgUid = NULL;
  208.     masterPtr->fileString = NULL;
  209.     masterPtr->dataString = NULL;
  210.     masterPtr->maskFileString = NULL;
  211.     masterPtr->maskDataString = NULL;
  212.     masterPtr->instancePtr = NULL;
  213.     if (ImgBmapConfigureMaster(masterPtr, argc, argv, 0) != TCL_OK) {
  214.     ImgBmapDelete((ClientData) masterPtr);
  215.     return TCL_ERROR;
  216.     }
  217.     *clientDataPtr = (ClientData) masterPtr;
  218.     return TCL_OK;
  219. }
  220.  
  221. /*
  222.  *----------------------------------------------------------------------
  223.  *
  224.  * ImgBmapConfigureMaster --
  225.  *
  226.  *    This procedure is called when a bitmap image is created or
  227.  *    reconfigured.  It process configuration options and resets
  228.  *    any instances of the image.
  229.  *
  230.  * Results:
  231.  *    A standard Tcl return value.  If TCL_ERROR is returned then
  232.  *    an error message is left in masterPtr->interp->result.
  233.  *
  234.  * Side effects:
  235.  *    Existing instances of the image will be redisplayed to match
  236.  *    the new configuration options.
  237.  *
  238.  *----------------------------------------------------------------------
  239.  */
  240.  
  241. static int
  242. ImgBmapConfigureMaster(masterPtr, argc, argv, flags)
  243.     BitmapMaster *masterPtr;    /* Pointer to data structure describing
  244.                  * overall bitmap image to (reconfigure). */
  245.     int argc;            /* Number of entries in argv. */
  246.     char **argv;        /* Pairs of configuration options for image. */
  247.     int flags;            /* Flags to pass to Tk_ConfigureWidget,
  248.                  * such as TK_CONFIG_ARGV_ONLY. */
  249. {
  250.     BitmapInstance *instancePtr;
  251.     int maskWidth, maskHeight;
  252.  
  253.     if (Tk_ConfigureWidget(masterPtr->interp, Tk_MainWindow(masterPtr->interp),
  254.         configSpecs, argc, argv, (char *) masterPtr, flags)
  255.         != TCL_OK) {
  256.     return TCL_ERROR;
  257.     }
  258.  
  259.     /*
  260.      * Parse the bitmap and/or mask to create binary data.  Make sure that
  261.      * the bitmap and mask have the same dimensions.
  262.      */
  263.  
  264.     if (masterPtr->data != NULL) {
  265.     ckfree(masterPtr->data);
  266.     masterPtr->data = NULL;
  267.     }
  268.     if ((masterPtr->fileString != NULL) || (masterPtr->dataString != NULL)) {
  269.     masterPtr->data = GetBitmapData(masterPtr->interp,
  270.         masterPtr->dataString, masterPtr->fileString,
  271.         &masterPtr->width, &masterPtr->height);
  272.     if (masterPtr->data == NULL) {
  273.         return TCL_ERROR;
  274.     }
  275.     }
  276.     if (masterPtr->maskData != NULL) {
  277.     ckfree(masterPtr->maskData);
  278.     masterPtr->maskData = NULL;
  279.     }
  280.     if ((masterPtr->maskFileString != NULL)
  281.         || (masterPtr->maskDataString != NULL)) {
  282.     if (masterPtr->data == NULL) {
  283.         masterPtr->interp->result = "can't have mask without bitmap";
  284.         return TCL_ERROR;
  285.     }
  286.     masterPtr->maskData = GetBitmapData(masterPtr->interp,
  287.         masterPtr->maskDataString, masterPtr->maskFileString,
  288.         &maskWidth, &maskHeight);
  289.     if (masterPtr->maskData == NULL) {
  290.         return TCL_ERROR;
  291.     }
  292.     if ((maskWidth != masterPtr->width)
  293.         || (maskHeight != masterPtr->height)) {
  294.         ckfree(masterPtr->maskData);
  295.         masterPtr->maskData = NULL;
  296.         masterPtr->interp->result = "bitmap and mask have different sizes";
  297.         return TCL_ERROR;
  298.     }
  299.     }
  300.  
  301.     /*
  302.      * Cycle through all of the instances of this image, regenerating
  303.      * the information for each instance.  Then force the image to be
  304.      * redisplayed everywhere that it is used.
  305.      */
  306.  
  307.     for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
  308.         instancePtr = instancePtr->nextPtr) {
  309.     ImgBmapConfigureInstance(instancePtr);
  310.     }
  311.     Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width,
  312.         masterPtr->height, masterPtr->width, masterPtr->height);
  313.     return TCL_OK;
  314. }
  315.  
  316. /*
  317.  *----------------------------------------------------------------------
  318.  *
  319.  * ImgBmapConfigureInstance --
  320.  *
  321.  *    This procedure is called to create displaying information for
  322.  *    a bitmap image instance based on the configuration information
  323.  *    in the master.  It is invoked both when new instances are
  324.  *    created and when the master is reconfigured.
  325.  *
  326.  * Results:
  327.  *    None.
  328.  *
  329.  * Side effects:
  330.  *    Generates errors via Tk_BackgroundError if there are problems
  331.  *    in setting up the instance.
  332.  *
  333.  *----------------------------------------------------------------------
  334.  */
  335.  
  336. static void
  337. ImgBmapConfigureInstance(instancePtr)
  338.     BitmapInstance *instancePtr;    /* Instance to reconfigure. */
  339. {
  340.     BitmapMaster *masterPtr = instancePtr->masterPtr;
  341.     XColor *colorPtr;
  342.     XGCValues gcValues;
  343.     GC gc;
  344.     unsigned int mask;
  345.  
  346.     /*
  347.      * For each of the options in masterPtr, translate the string
  348.      * form into an internal form appropriate for instancePtr.
  349.      */
  350.  
  351.     if (*masterPtr->bgUid != 0) {
  352.     colorPtr = Tk_GetColor(masterPtr->interp, instancePtr->tkwin,
  353.         masterPtr->bgUid);
  354.     if (colorPtr == NULL) {
  355.         goto error;
  356.     }
  357.     } else {
  358.     colorPtr = NULL;
  359.     }
  360.     if (instancePtr->bg != NULL) {
  361.     Tk_FreeColor(instancePtr->bg);
  362.     }
  363.     instancePtr->bg = colorPtr;
  364.  
  365.     colorPtr = Tk_GetColor(masterPtr->interp, instancePtr->tkwin,
  366.         masterPtr->fgUid);
  367.     if (colorPtr == NULL) {
  368.     goto error;
  369.     }
  370.     if (instancePtr->fg != NULL) {
  371.     Tk_FreeColor(instancePtr->fg);
  372.     }
  373.     instancePtr->fg = colorPtr;
  374.  
  375.     if (instancePtr->bitmap != None) {
  376.     XFreePixmap(Tk_Display(instancePtr->tkwin), instancePtr->bitmap);
  377.     instancePtr->bitmap = None;
  378.     }
  379.     if (masterPtr->data != NULL) {
  380.     instancePtr->bitmap = XCreateBitmapFromData(
  381.         Tk_Display(instancePtr->tkwin),
  382.         RootWindowOfScreen(Tk_Screen(instancePtr->tkwin)),
  383.         masterPtr->data, (unsigned) masterPtr->width,
  384.         (unsigned) masterPtr->height);
  385.     }
  386.  
  387.     if (instancePtr->mask != None) {
  388.     XFreePixmap(Tk_Display(instancePtr->tkwin), instancePtr->mask);
  389.     instancePtr->mask = None;
  390.     }
  391.     if (masterPtr->maskData != NULL) {
  392.     instancePtr->mask = XCreateBitmapFromData(
  393.         Tk_Display(instancePtr->tkwin),
  394.         RootWindowOfScreen(Tk_Screen(instancePtr->tkwin)),
  395.         masterPtr->maskData, (unsigned) masterPtr->width,
  396.         (unsigned) masterPtr->height);
  397.     }
  398.  
  399.     if (masterPtr->data != NULL) {
  400.     gcValues.foreground = instancePtr->fg->pixel;
  401.     gcValues.graphics_exposures = False;
  402.     mask = GCForeground|GCGraphicsExposures;
  403.     if (instancePtr->bg != NULL) {
  404.         gcValues.background = instancePtr->bg->pixel;
  405.         mask |= GCBackground;
  406.         if (instancePtr->mask != None) {
  407.         gcValues.clip_mask = instancePtr->mask;
  408.         mask |= GCClipMask;
  409.         }
  410.     } else {
  411.         gcValues.clip_mask = instancePtr->bitmap;
  412.         mask |= GCClipMask;
  413.     }
  414.     gc = Tk_GetGC(instancePtr->tkwin, mask, &gcValues);
  415.     } else {
  416.     gc = None;
  417.     }
  418.     if (instancePtr->gc != None) {
  419.     Tk_FreeGC(Tk_Display(instancePtr->tkwin), instancePtr->gc);
  420.     }
  421.     instancePtr->gc = gc;
  422.     return;
  423.  
  424.     error:
  425.     /*
  426.      * An error occurred: clear the graphics context in the instance to
  427.      * make it clear that this instance cannot be displayed.  Then report
  428.      * the error.
  429.      */
  430.  
  431.     if (instancePtr->gc != None) {
  432.     Tk_FreeGC(Tk_Display(instancePtr->tkwin), instancePtr->gc);
  433.     }
  434.     instancePtr->gc = None;
  435.     Tcl_AddErrorInfo(masterPtr->interp, "\n    (while configuring image \"");
  436.     Tcl_AddErrorInfo(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
  437.     Tcl_AddErrorInfo(masterPtr->interp, "\")");
  438.     Tk_BackgroundError(masterPtr->interp);
  439. }
  440.  
  441. /*
  442.  *----------------------------------------------------------------------
  443.  *
  444.  * GetBitmapData --
  445.  *
  446.  *    Given a file name or ASCII string, this procedure parses the
  447.  *    file or string contents to produce binary data for a bitmap.
  448.  *
  449.  * Results:
  450.  *    If the bitmap description was parsed successfully then the
  451.  *    return value is a malloc-ed array containing the bitmap data.
  452.  *    The dimensions of the data are stored in *widthPtr and *heightPtr.
  453.  *    If an error occurred, NULL is returned and an error message is
  454.  *    left in interp->result.
  455.  *
  456.  * Side effects:
  457.  *    A bitmap is created.
  458.  *
  459.  *----------------------------------------------------------------------
  460.  */
  461.  
  462. static char *
  463. GetBitmapData(interp, string, fileName, widthPtr, heightPtr)
  464.     Tcl_Interp *interp;            /* For reporting errors. */
  465.     char *string;            /* String describing bitmap.  May
  466.                      * be NULL. */
  467.     char *fileName;            /* Name of file containing bitmap
  468.                      * description.  Used only if string
  469.                      * is NULL.  Must not be NULL if
  470.                      * string is NULL. */
  471.     int *widthPtr, *heightPtr;        /* Dimensions of bitmap get returned
  472.                      * here. */
  473. {
  474.     int width, height, numBytes;
  475.     char *p, *end, *expandedFileName;
  476.     ParseInfo pi;
  477.     char *data = NULL;
  478.     Tcl_DString buffer;
  479.  
  480.     pi.string = string;
  481.     if (string == NULL) {
  482.     expandedFileName = Tcl_TildeSubst(interp, fileName, &buffer);
  483.     if (expandedFileName == NULL) {
  484.         return NULL;
  485.     }
  486.     pi.f = fopen(expandedFileName, "r");
  487.     Tcl_DStringFree(&buffer);
  488.     if (pi.f == NULL) {
  489.         Tcl_AppendResult(interp, "couldn't read bitmap file \"",
  490.             fileName, "\": ", Tcl_PosixError(interp), (char *) NULL);
  491.         return NULL;
  492.     }
  493.     } else {
  494.     pi.f = NULL;
  495.     }
  496.  
  497.     /*
  498.      * Parse the lines that define the dimensions of the bitmap,
  499.      * plus the first line that defines the bitmap data (it declares
  500.      * the name of a data variable but doesn't include any actual
  501.      * data).  These lines look something like the following:
  502.      *
  503.      *        #define foo_width 16
  504.      *        #define foo_height 16
  505.      *        #define foo_x_hot 3
  506.      *        #define foo_y_hot 3
  507.      *        static char foo_bits[] = {
  508.      *
  509.      * The x_hot and y_hot lines may or may not be present.  It's
  510.      * important to check for "char" in the last line, in order to
  511.      * reject old X10-style bitmaps that used shorts.
  512.      */
  513.  
  514.     width = 0;
  515.     height = 0;
  516.     while (1) {
  517.     if (NextBitmapWord(&pi) != TCL_OK) {
  518.         goto error;
  519.     }
  520.     if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_')
  521.         && (strcmp(pi.word+pi.wordLength-6, "_width") == 0)) {
  522.         if (NextBitmapWord(&pi) != TCL_OK) {
  523.         goto error;
  524.         }
  525.         width = strtol(pi.word, &end, 0);
  526.         if ((end == pi.word) || (*end != 0)) {
  527.         goto error;
  528.         }
  529.     } else if ((pi.wordLength >= 7) && (pi.word[pi.wordLength-7] == '_')
  530.         && (strcmp(pi.word+pi.wordLength-7, "_height") == 0)) {
  531.         if (NextBitmapWord(&pi) != TCL_OK) {
  532.         goto error;
  533.         }
  534.         height = strtol(pi.word, &end, 0);
  535.         if ((end == pi.word) || (*end != 0)) {
  536.         goto error;
  537.         }
  538.     } else if ((pi.word[0] == 'c') && (strcmp(pi.word, "char") == 0)) {
  539.         while (1) {
  540.         if (NextBitmapWord(&pi) != TCL_OK) {
  541.             goto error;
  542.         }
  543.         if ((pi.word[0] == '{') && (pi.word[1] == 0)) {
  544.             goto getData;
  545.         }
  546.         }
  547.     } else if ((pi.word[0] == '{') && (pi.word[1] == 0)) {
  548.         Tcl_AppendResult(interp, "format error in bitmap data; ",
  549.             "looks like it's an obsolete X10 bitmap file",
  550.             (char *) NULL);
  551.         goto errorCleanup;
  552.     }
  553.     }
  554.  
  555.     /*
  556.      * Now we've read everything but the data.  Allocate an array
  557.      * and read in the data.
  558.      */
  559.  
  560.     getData:
  561.     if ((width <= 0) || (height <= 0)) {
  562.     goto error;
  563.     }
  564.     numBytes = ((width+7)/8) * height;
  565.     data = (char *) ckalloc((unsigned) numBytes);
  566.     for (p = data; numBytes > 0; p++, numBytes--) {
  567.     if (NextBitmapWord(&pi) != TCL_OK) {
  568.         goto error;
  569.     }
  570.     *p = strtol(pi.word, &end, 0);
  571.     if (end == pi.word) {
  572.         goto error;
  573.     }
  574.     }
  575.  
  576.     /*
  577.      * All done.  Clean up and return.
  578.      */
  579.  
  580.     if (pi.f != NULL) {
  581.     fclose(pi.f);
  582.     }
  583.     *widthPtr = width;
  584.     *heightPtr = height;
  585.     return data;
  586.  
  587.     error:
  588.     interp->result = "format error in bitmap data";
  589.     errorCleanup:
  590.     if (data != NULL) {
  591.     ckfree(data);
  592.     }
  593.     if (pi.f != NULL) {
  594.     fclose(pi.f);
  595.     }
  596.     return NULL;
  597. }
  598.  
  599. /*
  600.  *----------------------------------------------------------------------
  601.  *
  602.  * NextBitmapWord --
  603.  *
  604.  *    This procedure retrieves the next word of information (stuff
  605.  *    between commas or white space) from a bitmap description.
  606.  *
  607.  * Results:
  608.  *    Returns TCL_OK if all went well.  In this case the next word,
  609.  *    and its length, will be availble in *parseInfoPtr.  If the end
  610.  *    of the bitmap description was reached then TCL_ERROR is returned.
  611.  *
  612.  * Side effects:
  613.  *    None.
  614.  *
  615.  *----------------------------------------------------------------------
  616.  */
  617.  
  618. static int
  619. NextBitmapWord(parseInfoPtr)
  620.     ParseInfo *parseInfoPtr;        /* Describes what we're reading
  621.                      * and where we are in it. */
  622. {
  623.     char *src, *dst;
  624.     int c;
  625.  
  626.     parseInfoPtr->wordLength = 0;
  627.     dst = parseInfoPtr->word;
  628.     if (parseInfoPtr->string != NULL) {
  629.     for (src = parseInfoPtr->string; isspace(UCHAR(*src)) || (*src == ',');
  630.         src++) {
  631.         if (*src == 0) {
  632.         return TCL_ERROR;
  633.         }
  634.     }
  635.     for ( ; !isspace(UCHAR(*src)) && (*src != ',') && (*src != 0); src++) {
  636.         *dst = *src;
  637.         dst++;
  638.         parseInfoPtr->wordLength++;
  639.         if (parseInfoPtr->wordLength > MAX_WORD_LENGTH) {
  640.         return TCL_ERROR;
  641.         }
  642.     }
  643.     parseInfoPtr->string = src;
  644.     } else {
  645.     for (c = getc(parseInfoPtr->f); isspace(UCHAR(c)) || (c == ',');
  646.         c = getc(parseInfoPtr->f)) {
  647.         if (c == EOF) {
  648.         return TCL_ERROR;
  649.         }
  650.     }
  651.     for ( ; !isspace(UCHAR(c)) && (c != ',') && (c != EOF);
  652.         c = getc(parseInfoPtr->f)) {
  653.         *dst = c;
  654.         dst++;
  655.         parseInfoPtr->wordLength++;
  656.         if (parseInfoPtr->wordLength > MAX_WORD_LENGTH) {
  657.         return TCL_ERROR;
  658.         }
  659.     }
  660.     }
  661.     if (parseInfoPtr->wordLength == 0) {
  662.     return TCL_ERROR;
  663.     }
  664.     parseInfoPtr->word[parseInfoPtr->wordLength] = 0;
  665.     return TCL_OK;
  666. }
  667.  
  668. /*
  669.  *--------------------------------------------------------------
  670.  *
  671.  * ImgBmapCmd --
  672.  *
  673.  *    This procedure is invoked to process the Tcl command
  674.  *    that corresponds to an image managed by this module.
  675.  *    See the user documentation for details on what it does.
  676.  *
  677.  * Results:
  678.  *    A standard Tcl result.
  679.  *
  680.  * Side effects:
  681.  *    See the user documentation.
  682.  *
  683.  *--------------------------------------------------------------
  684.  */
  685.  
  686. static int
  687. ImgBmapCmd(clientData, interp, argc, argv)
  688.     ClientData clientData;    /* Information about button widget. */
  689.     Tcl_Interp *interp;        /* Current interpreter. */
  690.     int argc;            /* Number of arguments. */
  691.     char **argv;        /* Argument strings. */
  692. {
  693.     BitmapMaster *masterPtr = (BitmapMaster *) clientData;
  694.     int c, code;
  695.     size_t length;
  696.  
  697.     if (argc < 2) {
  698.     sprintf(interp->result,
  699.         "wrong # args: should be \"%.50s option ?arg arg ...?\"",
  700.         argv[0]);
  701.     return TCL_ERROR;
  702.     }
  703.     c = argv[1][0];
  704.     length = strlen(argv[1]);
  705.     if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
  706.         && (length >= 2)) {
  707.     if (argc != 3) {
  708.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  709.             argv[0], " cget option\"",
  710.             (char *) NULL);
  711.         return TCL_ERROR;
  712.     }
  713.     return Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs,
  714.         (char *) masterPtr, argv[2], 0);
  715.     } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
  716.         && (length >= 2)) {
  717.     if (argc == 2) {
  718.         code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
  719.             configSpecs, (char *) masterPtr, (char *) NULL, 0);
  720.     } else if (argc == 3) {
  721.         code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
  722.             configSpecs, (char *) masterPtr, argv[2], 0);
  723.     } else {
  724.         code = ImgBmapConfigureMaster(masterPtr, argc-2, argv+2,
  725.             TK_CONFIG_ARGV_ONLY);
  726.     }
  727.     return code;
  728.     } else {
  729.     Tcl_AppendResult(interp, "bad option \"", argv[1],
  730.         "\": must be cget or configure", (char *) NULL);
  731.     return TCL_ERROR;
  732.     }
  733. }
  734.  
  735. /*
  736.  *----------------------------------------------------------------------
  737.  *
  738.  * ImgBmapGet --
  739.  *
  740.  *    This procedure is called for each use of a bitmap image in a
  741.  *    widget.
  742.  *
  743.  * Results:
  744.  *    The return value is a token for the instance, which is passed
  745.  *    back to us in calls to ImgBmapDisplay and ImgBmapFree.
  746.  *
  747.  * Side effects:
  748.  *    A data structure is set up for the instance (or, an existing
  749.  *    instance is re-used for the new one).
  750.  *
  751.  *----------------------------------------------------------------------
  752.  */
  753.  
  754. static ClientData
  755. ImgBmapGet(tkwin, masterData)
  756.     Tk_Window tkwin;        /* Window in which the instance will be
  757.                  * used. */
  758.     ClientData masterData;    /* Pointer to our master structure for the
  759.                  * image. */
  760. {
  761.     BitmapMaster *masterPtr = (BitmapMaster *) masterData;
  762.     BitmapInstance *instancePtr;
  763.  
  764.     /*
  765.      * See if there is already an instance for this window.  If so
  766.      * then just re-use it.
  767.      */
  768.  
  769.     for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
  770.         instancePtr = instancePtr->nextPtr) {
  771.     if (instancePtr->tkwin == tkwin) {
  772.         instancePtr->refCount++;
  773.         return (ClientData) instancePtr;
  774.     }
  775.     }
  776.  
  777.     /*
  778.      * The image isn't already in use in this window.  Make a new
  779.      * instance of the image.
  780.      */
  781.  
  782.     instancePtr = (BitmapInstance *) ckalloc(sizeof(BitmapInstance));
  783.     instancePtr->refCount = 1;
  784.     instancePtr->masterPtr = masterPtr;
  785.     instancePtr->tkwin = tkwin;
  786.     instancePtr->fg = NULL;
  787.     instancePtr->bg = NULL;
  788.     instancePtr->bitmap = None;
  789.     instancePtr->mask = None;
  790.     instancePtr->gc = None;
  791.     instancePtr->nextPtr = masterPtr->instancePtr;
  792.     masterPtr->instancePtr = instancePtr;
  793.     ImgBmapConfigureInstance(instancePtr);
  794.  
  795.     /*
  796.      * If this is the first instance, must set the size of the image.
  797.      */
  798.  
  799.     if (instancePtr->nextPtr == NULL) {
  800.     Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, masterPtr->width,
  801.         masterPtr->height);
  802.     }
  803.  
  804.     return (ClientData) instancePtr;
  805. }
  806.  
  807. /*
  808.  *----------------------------------------------------------------------
  809.  *
  810.  * ImgBmapDisplay --
  811.  *
  812.  *    This procedure is invoked to draw a bitmap image.
  813.  *
  814.  * Results:
  815.  *    None.
  816.  *
  817.  * Side effects:
  818.  *    A portion of the image gets rendered in a pixmap or window.
  819.  *
  820.  *----------------------------------------------------------------------
  821.  */
  822.  
  823. static void
  824. ImgBmapDisplay(clientData, display, drawable, imageX, imageY, width,
  825.     height, drawableX, drawableY)
  826.     ClientData clientData;    /* Pointer to BitmapInstance structure for
  827.                  * for instance to be displayed. */
  828.     Display *display;        /* Display on which to draw image. */
  829.     Drawable drawable;        /* Pixmap or window in which to draw image. */
  830.     int imageX, imageY;        /* Upper-left corner of region within image
  831.                  * to draw. */
  832.     int width, height;        /* Dimensions of region within image to draw. */
  833.     int drawableX, drawableY;    /* Coordinates within drawable that
  834.                  * correspond to imageX and imageY. */
  835. {
  836.     BitmapInstance *instancePtr = (BitmapInstance *) clientData;
  837.     int masking;
  838.  
  839.     /*
  840.      * If there's no graphics context, it means that an error occurred
  841.      * while creating the image instance so it can't be displayed.
  842.      */
  843.  
  844.     if (instancePtr->gc == None) {
  845.     return;
  846.     }
  847.  
  848.     /*
  849.      * If masking is in effect, must modify the mask origin within
  850.      * the graphics context to line up with the image's origin.
  851.      * Then draw the image and reset the clip origin, if there's
  852.      * a mask.
  853.      */
  854.  
  855.     masking = (instancePtr->mask != None) || (instancePtr->bg == NULL);
  856.     if (masking) {
  857.     XSetClipOrigin(display, instancePtr->gc, drawableX - imageX,
  858.         drawableY - imageY);
  859.     }
  860.     XCopyPlane(display, instancePtr->bitmap, drawable, instancePtr->gc,
  861.         imageX, imageY, (unsigned) width, (unsigned) height,
  862.         drawableX, drawableY, 1);
  863.     if (masking) {
  864.     XSetClipOrigin(display, instancePtr->gc, 0, 0);
  865.     }
  866. }
  867.  
  868. /*
  869.  *----------------------------------------------------------------------
  870.  *
  871.  * ImgBmapFree --
  872.  *
  873.  *    This procedure is called when a widget ceases to use a
  874.  *    particular instance of an image.
  875.  *
  876.  * Results:
  877.  *    None.
  878.  *
  879.  * Side effects:
  880.  *    Internal data structures get cleaned up.
  881.  *
  882.  *----------------------------------------------------------------------
  883.  */
  884.  
  885. static void
  886. ImgBmapFree(clientData, display)
  887.     ClientData clientData;    /* Pointer to BitmapInstance structure for
  888.                  * for instance to be displayed. */
  889.     Display *display;        /* Display containing window that used image. */
  890. {
  891.     BitmapInstance *instancePtr = (BitmapInstance *) clientData;
  892.     BitmapInstance *prevPtr;
  893.  
  894.     instancePtr->refCount--;
  895.     if (instancePtr->refCount > 0) {
  896.     return;
  897.     }
  898.  
  899.     /*
  900.      * There are no more uses of the image within this widget.  Free
  901.      * the instance structure.
  902.      */
  903.  
  904.     if (instancePtr->fg != NULL) {
  905.     Tk_FreeColor(instancePtr->fg);
  906.     }
  907.     if (instancePtr->bg != NULL) {
  908.     Tk_FreeColor(instancePtr->bg);
  909.     }
  910.     if (instancePtr->bitmap != None) {
  911.     XFreePixmap(display, instancePtr->bitmap);
  912.     }
  913.     if (instancePtr->mask != None) {
  914.     XFreePixmap(display, instancePtr->mask);
  915.     }
  916.     if (instancePtr->gc != None) {
  917.     Tk_FreeGC(display, instancePtr->gc);
  918.     }
  919.     if (instancePtr->masterPtr->instancePtr == instancePtr) {
  920.     instancePtr->masterPtr->instancePtr = instancePtr->nextPtr;
  921.     } else {
  922.     for (prevPtr = instancePtr->masterPtr->instancePtr;
  923.         prevPtr->nextPtr != instancePtr; prevPtr = prevPtr->nextPtr) {
  924.         /* Empty loop body */
  925.     }
  926.     prevPtr->nextPtr = instancePtr->nextPtr;
  927.     }
  928.     ckfree((char *) instancePtr);
  929. }
  930.  
  931. /*
  932.  *----------------------------------------------------------------------
  933.  *
  934.  * ImgBmapDelete --
  935.  *
  936.  *    This procedure is called by the image code to delete the
  937.  *    master structure for an image.
  938.  *
  939.  * Results:
  940.  *    None.
  941.  *
  942.  * Side effects:
  943.  *    Resources associated with the image get freed.
  944.  *
  945.  *----------------------------------------------------------------------
  946.  */
  947.  
  948. static void
  949. ImgBmapDelete(masterData)
  950.     ClientData masterData;    /* Pointer to BitmapMaster structure for
  951.                  * image.  Must not have any more instances. */
  952. {
  953.     BitmapMaster *masterPtr = (BitmapMaster *) masterData;
  954.  
  955.     if (masterPtr->instancePtr != NULL) {
  956.     panic("tried to delete bitmap image when instances still exist");
  957.     }
  958.     masterPtr->tkMaster = NULL;
  959.     if (masterPtr->imageCmd != NULL) {
  960.     Tcl_DeleteCommand(masterPtr->interp,
  961.         Tcl_GetCommandName(masterPtr->interp, masterPtr->imageCmd));
  962.     }
  963.     if (masterPtr->data != NULL) {
  964.     ckfree(masterPtr->data);
  965.     }
  966.     if (masterPtr->maskData != NULL) {
  967.     ckfree(masterPtr->maskData);
  968.     }
  969.     Tk_FreeOptions(configSpecs, (char *) masterPtr, (Display *) NULL, 0);
  970.     ckfree((char *) masterPtr);
  971. }
  972.  
  973. /*
  974.  *----------------------------------------------------------------------
  975.  *
  976.  * ImgBmapCmdDeletedProc --
  977.  *
  978.  *    This procedure is invoked when the image command for an image
  979.  *    is deleted.  It deletes the image.
  980.  *
  981.  * Results:
  982.  *    None.
  983.  *
  984.  * Side effects:
  985.  *    The image is deleted.
  986.  *
  987.  *----------------------------------------------------------------------
  988.  */
  989.  
  990. static void
  991. ImgBmapCmdDeletedProc(clientData)
  992.     ClientData clientData;    /* Pointer to BitmapMaster structure for
  993.                  * image. */
  994. {
  995.     BitmapMaster *masterPtr = (BitmapMaster *) clientData;
  996.  
  997.     masterPtr->imageCmd = NULL;
  998.     if (masterPtr->tkMaster != NULL) {
  999.     Tk_DeleteImage(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
  1000.     }
  1001. }
  1002.